#ifndef STRATUM_JOB_H
#define STRATUM_JOB_H
#include <vector>
#include "coind.h"
#include "stratum.h"

#define MAX_AUX 32
#define STRATUM_JOB_MAXSUBIDS		200

class StratumRemote;

class StratumJobValues {
public:
    char m_coinbase[4*1024];
    char m_merkle_root_be[1024];

    char m_header[1024];
    char m_header_be[1024];

    unsigned char m_header_bin[1024];

    char m_hash_hex[1024];
    char m_hash_be[1024];
    unsigned char m_hash_bin[1024];
};


class StratumJobTemplate {
public:
    int m_created;
    char m_flags[64];

    char m_prevhash_hex[512];
    char m_prehash_be[512];

    char m_extradata_hex[512];
    char m_extradata_be[512];

    char m_claim_hex[128];
    char m_clain_be[128];

    int m_tx_count;
    char m_tx_merkles[STRATUM_SMALL_BUF_SIZE];

    std::vector<std::string> m_tx_steps;
    std::vector<std::string> m_tx_data;

    char m_version[32];
    char m_nbits[32];
    char m_ntime[32];

    int m_height;
    int m_target;

    json_int_t m_values;

    char m_coinb1[4*1024];
    char m_coinb2[4*1024];
    char m_header[256];
    bool m_has_segwit_txs;
    int m_filtered_txs_fee;

    int m_aux_size;
    StratumCoindAux* m_aux[MAX_AUX];
};

class StratumJob: public StratumObject {
public:
    bool m_block_found;
    char m_name[1024];

    int m_count;
    double m_speed;
    double m_max_speed;
    double m_profit;

    StratumCoind* m_coind;
    StratumRemote* m_remote;
    StratumJobTemplate* m_templ;

    bool m_remote_subids[STRATUM_JOB_MAXSUBIDS];
};

inline void jobDel(StratumObject* obj) {
    StratumJob* job = (StratumJob*)obj;
    if (!job) {
        return;
    }
    if (job->m_templ && job->m_templ->m_tx_count) {
        job->m_templ->m_tx_steps.clear();
        job->m_templ->m_tx_data.clear();
    }
    if (job->m_templ) {
        delete job->m_templ;
    }
    delete job;
}

int jobGetJobId();
void jobSort();
void jobRelockClients(int jobIdOld, int jobIdNew);
void jobUnlockClients(StratumJob* job= nullptr);
void jobAssignLockedClients(StratumJob* job);

bool jobCanMine(StratumJob* job);
void jobResetClients(StratumJob* job= nullptr);
bool jobHasFreeClient();


void jobSendJobId(StratumClient* client, int jobId);
void jobSendLast(StratumClient* client);
void jobBroadcast(StratumJob* job);

void* jobThread(void* p);
void jobSignal();
void jobUpdate();
void jobInit();

void coinbaseCreate(StratumCoind* coind, StratumJobTemplate* templ, json_value* jsonResult);

std::vector<std::string> coindAuxHashList(StratumCoindAux** aux, int size);
std::vector<std::string> coindAuxMerkleBranch(StratumCoindAux** aux, int size, int index);
void coindAuxBuildAuxs(StratumJobTemplate* templ);

#endif //STRATUM_JOB_H
